package com.cwj.mylibrary;

import android.annotation.SuppressLint;

import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

/**
 * 日期工具类
 */
public class TimeUtils {

    /**
     * 时间转换成字符串,默认为"yyyy-MM-dd HH:mm:ss"
     *
     * @param time 时间
     */
    public static String dateToString(long time) {
        return dateToString(time, "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 时间转换成字符串,指定格式
     *
     * @param time   时间
     * @param format 时间格式
     */
    public static String dateToString(long time, String format) {
        Date date = new Date(time);
        @SuppressLint("SimpleDateFormat") SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
        return simpleDateFormat.format(date);
    }

    /**
     * 获取当前的时间戳
     */
    public static long getTimeStame() {
        //将毫秒值转换为String类型数据
        return System.currentTimeMillis();
    }

    /**
     * 获取当前时间为本月的第几周
     *
     * @return 本月的第几周
     */
    public static int getCurrentWeekOfMonth() {
        Calendar calendar = Calendar.getInstance();
        return calendar.get(Calendar.WEEK_OF_MONTH);
    }

    /**
     * 获取当前时间为本周的第几天
     *
     * @return 本周的第几天（1代表周一，7代表周日）
     */
    public static int getCurrentDayOfWeek() {
        int dayOfWeekValue;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            //系统大于等于26（8.0）本周的第几天（1代表周一，7代表周日），从周一开始
            //即dayOfWeek.getValue()返回值1代表周一，2代表周二，3代表周三，4代表周四，5代表周五，6代表周六，7代表周日
            LocalDate currentDate = LocalDate.now();
            DayOfWeek dayOfWeek = currentDate.getDayOfWeek();
            dayOfWeekValue = dayOfWeek.getValue();
        } else {
            //系统小于26（8.0）本周的第几天（1代表周日，7代表周六），从周日开始
            //即calendar.get(Calendar.DAY_OF_WEEK)返回值1代表周日，2代表周一，3代表周二，4代表周三，5代表周四，6代表周五，7代表周六
            Calendar calendar = Calendar.getInstance();
            if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                //如果返回值为1（周日），把返回值+6，和8.0及以上（LocalDate获取）返回值保持一致
                dayOfWeekValue = calendar.get(Calendar.DAY_OF_WEEK) + 6;
            } else {
                //如果返回值为除1（周日）外的值，把返回值-16，和8.0及以上（LocalDate获取）返回值保持一致
                dayOfWeekValue = calendar.get(Calendar.DAY_OF_WEEK) - 1;
            }
        }
        return dayOfWeekValue;
    }

    /**
     * 返回当前日期是星期几
     *
     * @return 例如：星期日、星期一、星期六等等。
     */
    public static String getCurrentDayOfWeekText() {
        Calendar calendar = Calendar.getInstance();
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        // 获取星期几文本
        DateFormatSymbols symbols = new DateFormatSymbols(Locale.getDefault());
        String[] dayOfWeekTexts = symbols.getWeekdays();
        if (dayOfWeek >= Calendar.SUNDAY && dayOfWeek <= Calendar.SATURDAY) {
            return dayOfWeekTexts[dayOfWeek];
        } else {
            return "";
        }
    }

    /**
     * 判断指定时间是否在时间区间内
     *
     * @param time      待判断的时间
     * @param startTime 时间区间的开始时间
     * @param endTime   时间区间的结束时间
     * @return 如果指定时间在时间区间内，返回 true；否则返回 false
     */
    public static boolean isTimeInRange(Calendar time, Calendar startTime, Calendar endTime) {
        return time.compareTo(startTime) >= 0 && time.compareTo(endTime) <= 0;
    }

    /**
     * 判断指定时间是否在时间区间内
     *
     * @param currentTime 待判断的时间
     * @param startTime   时间区间的开始时间
     * @param endTime     时间区间的结束时间
     * @return 如果指定时间在时间区间内，返回 true；否则返回 false
     */
    public static boolean isInTimeRange(Date currentTime, Date startTime, Date endTime) {
        long currentTimeMillis = currentTime.getTime();
        return currentTimeMillis >= startTime.getTime() && currentTimeMillis <= endTime.getTime();
    }

    /**
     * 判断指定时间是否在给定时间区间内
     *
     * @param time      待判断的时间
     * @param startTime 时间区间的开始时间
     * @param endTime   时间区间的结束时间
     * @return 如果指定时间在时间区间内，返回 true；否则返回 false
     */
    public static boolean isInTimeRange2(Date time, Date startTime, Date endTime) {
        return time.after(startTime) && time.before(endTime);
    }

    /**
     * 求两个日期相差天数
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return 相差天数
     */
    public static long calculateDaysDifference(Date startDate, Date endDate) {
        long differenceMillis = endDate.getTime() - startDate.getTime();
        return TimeUnit.MILLISECONDS.toDays(differenceMillis);
    }

    /**
     * 返回友好时间跨度
     *
     * @param date 需要格式化的时间
     * @return the fit time span
     * return 小于1分钟，返回"刚刚"
     * return 小于1小时但大于0分钟，返回"X分钟前"
     * return 小于1天但大于0小时，返回"X小时前"
     * return 昨天，返回"昨天"
     * return 大于1天，返回"X天前"
     */
    public static String calculateTimeDifference(Date date) {
        long currentTime = System.currentTimeMillis();
        long timeDifference = currentTime - date.getTime();
        // 计算时间差对应的单位
        long seconds = timeDifference / 1000;
        long minutes = seconds / 60;
        long hours = minutes / 60;
        long days = hours / 24;

        if (days > 1) {
            // 大于1天，返回"X天前"
            return days + "天前";
        } else if (days == 1) {
            // 昨天，返回"昨天"
            return "昨天";
        } else if (hours > 0) {
            // 小于1天但大于0小时，返回"X小时前"
            return hours + "小时前";
        } else if (minutes > 0) {
            // 小于1小时但大于0分钟，返回"X分钟前"
            return minutes + "分钟前";
        } else {
            // 小于1分钟，返回"刚刚"
            return "刚刚";
        }
    }

    private static final TimeZone DEFAULT_TIMEZONE = TimeZone.getDefault();

    /**
     * 获取当前时间的字符串表示
     *
     * @param pattern 时间格式
     * @return 当前时间的字符串表示
     */
    public static String getCurrentDate(String pattern) {
        return formatToStr(new Date(), pattern);
    }

    /**
     * 将时间戳格式化为指定格式的字符串
     *
     * @param timestamp 时间戳
     * @param pattern   时间格式
     * @return 格式化后的时间字符串
     */
    public static String formatToStr(long timestamp, String pattern) {
        return formatToStr(new Date(timestamp), pattern);
    }

    /**
     * 将日期对象格式化为指定格式的字符串
     *
     * @param date    日期对象
     * @param pattern 时间格式
     * @return 格式化后的时间字符串
     */
    public static String formatToStr(Date date, String pattern) {
        DateFormat dateFormat = getDateFormat(pattern);
        return dateFormat.format(date);
    }

    /**
     * 获取指定格式的日期格式化对象
     *
     * @param pattern 时间格式
     * @return 日期格式化对象
     */
    private static DateFormat getDateFormat(String pattern) {
        @SuppressLint("SimpleDateFormat") SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        dateFormat.setTimeZone(DEFAULT_TIMEZONE);
        return dateFormat;
    }

    /**
     * 格式化字符串时间为指定格式
     *
     * @param dateString 字符串时间
     * @param format     格式
     * @return 格式化后的时间字符串
     */
    public static String formatStringDate(String dateString, String format) {
        @SuppressLint("SimpleDateFormat") SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        @SuppressLint("SimpleDateFormat") SimpleDateFormat outputFormat = new SimpleDateFormat(format);
        try {
            Date date = inputFormat.parse(dateString);
            if (date != null) {
                return outputFormat.format(date);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 获取当前时间的日期对象
     *
     * @return 当前时间的日期对象
     */
    public static Date getCurrentTime() {
        return new Date();
    }

    /**
     * 将日期对象格式化为指定格式的时间字符串
     *
     * @param date    日期对象
     * @param pattern 时间格式
     * @return 格式化后的时间字符串
     */
    public static String formatTime(Date date, String pattern) {
        @SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }

    /**
     * 解析指定格式的时间字符串为日期对象
     *
     * @param time    时间字符串
     * @param pattern 时间格式
     * @return 解析后的日期对象
     */
    public static Date parseTime(String time, String pattern) {
        @SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        try {
            return sdf.parse(time);
        } catch (java.text.ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 计算两个日期之间的时间差，返回指定时间单位的差值
     *
     * @param date1    第一个日期对象
     * @param date2    第二个日期对象
     * @param timeUnit 时间单位
     * @return 时间差的差值
     */
    public static long getTimeDifference(Date date1, Date date2, TimeUnit timeUnit) {
        long difference = date2.getTime() - date1.getTime();
        return timeUnit.convert(difference, TimeUnit.MILLISECONDS);
    }

    /**
     * 判断指定年份是否为闰年
     *
     * @param year 年份
     * @return 如果是闰年，返回 true；否则返回 false
     */
    public static boolean isLeapYear(int year) {
        return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
    }

    /**
     * 获取指定日期对象的年份
     *
     * @param date 日期对象
     * @return 年份
     */
    public static int getYearFromDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.YEAR);
    }

    /**
     * 获取指定日期对象的月份
     *
     * @param date 日期对象
     * @return 月份
     */
    public static int getMonthFromDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.MONTH) + 1;
    }

    /**
     * 获取指定日期对象的星期
     *
     * @param date 日期对象
     * @return 星期，1 表示星期一，2 表示星期二，依次类推
     */
    public static int getWeekdayFromDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int dayOfWeekValue;
        if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
            //如果返回值为1（周日），把返回值+6，和8.0及以上（LocalDate获取）返回值保持一致
            dayOfWeekValue = calendar.get(Calendar.DAY_OF_WEEK) + 6;
        } else {
            //如果返回值为除1（周日）外的值，把返回值-16，和8.0及以上（LocalDate获取）返回值保持一致
            dayOfWeekValue = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        }
        return dayOfWeekValue;
    }
}
